package com.jrx.anytxn.transaction.service.impl;

import com.jrx.anytxn.common.data.TxnRespCode;
import com.jrx.anytxn.common.exception.TxnBizException;
import com.jrx.anytxn.common.exception.TxnException;
import com.jrx.anytxn.common.function.UncheckedFunction;
import com.jrx.anytxn.common.uitl.BeanMapping;
import com.jrx.anytxn.common.uitl.BeanUtils;
import com.jrx.anytxn.common.uitl.CollectorsUtils;
import com.jrx.anytxn.common.uitl.DateUtils;
import com.jrx.anytxn.number.exception.SegmentException;
import com.jrx.anytxn.number.service.ISegmentService;
import com.jrx.anytxn.param.entity.PrDelqTable;
import com.jrx.anytxn.param.entity.PrPenaltyRateTable;
import com.jrx.anytxn.param.service.product.IDelqTableService;
import com.jrx.anytxn.param.service.product.IPrPenaltyRateTableService;
import com.jrx.anytxn.transaction.bean.*;
import com.jrx.anytxn.transaction.constant.TransBizConstant;
import com.jrx.anytxn.transaction.entity.*;
import com.jrx.anytxn.transaction.mapper.ext.ExtAmRepaymentPlanInfoMapper;
import com.jrx.anytxn.transaction.service.IAccountService;
import com.jrx.anytxn.transaction.service.IDealDelqService;
import com.jrx.anytxn.transaction.service.IDebtCalculationService;
import com.jrx.anytxn.transaction.service.IStrategySelector;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: anytxn-cf-transaction
 * @description: 延滞处理操作类
 * @author: xiaoyu.jing
 * @date: 2019-11-14 11:25
 **/
@Service
@CacheConfig(cacheNames = "DELQ")
public class DealDelqServiceImpl implements IDealDelqService {
    private static final Logger logger = LoggerFactory.getLogger(DealDelqServiceImpl.class);

    @Autowired
    private IDelqTableService delqTableService;
    @Autowired
    private ISegmentService segmentService;
    @Autowired
    private IAccountService accountService;
    @Autowired
    private IPrPenaltyRateTableService prPenaltyRateTableService;
    @Autowired
    private IStrategySelector strategySelector;
    @Resource
    private ExtAmRepaymentPlanInfoMapper extAmRepaymentPlanInfoMapper;


    /**
     * 构建延滞处理参数
     *
     * @param tenantId
     * @param delqId
     * @return
     */
    @Cacheable(key = "'delqParam_'+#tenantId+'_'+#delqId")
    @Override
    public DelqParamBean buildDqlqAccountBean(String tenantId, String delqId) throws TxnBizException {
        PrDelqTable table = delqTableService.findByDelqId(tenantId, delqId);
        logger.info("延滞参数table:{}", BeanUtils.toMap(table));
        DelqParamBean delqParamBean = new DelqParamBean();

        List<String> prinAndLoanTypeList = Arrays.asList(TransBizConstant.ACCOUNT_TYPE_05, TransBizConstant.ACCOUNT_TYPE_06);
        List<String> intrTypeList = Arrays.asList(TransBizConstant.ACCOUNT_TYPE_04, TransBizConstant.INTEREST_ACCRUAL_TYPE_66);
        List<String> pentIntrTypeList = Arrays.asList(TransBizConstant.ACCOUNT_TYPE_11, TransBizConstant.ACCOUNT_TYPE_12,
                TransBizConstant.INTEREST_ACCRUAL_TYPE_10, TransBizConstant.INTEREST_ACCRUAL_TYPE_20);

        //本金,订单会计状态-正常
        delqParamBean.getDelqAccountBeanList().add(new DelqAccountBean(prinAndLoanTypeList, TransBizConstant.ACCOUNTING_PHASE_0,
                TransBizConstant.TRANSFER_FLAG_1, 0, TransBizConstant.TXN_CODE_PRIN_TRAN_NOMAL, TransBizConstant.EVENT_CODE_T0));
        //本金,订单会计状态-逾期
        delqParamBean.getDelqAccountBeanList().add(new DelqAccountBean(prinAndLoanTypeList, TransBizConstant.ACCOUNTING_PHASE_1,
                table.getPrincipalOverdueFlag(), table.getOverdueDays(), TransBizConstant.TXN_CODE_PRIN_TRAN_OVER, TransBizConstant.EVENT_CODE_T1));
        //本金,订单会计状态-呆滞
        delqParamBean.getDelqAccountBeanList().add(new DelqAccountBean(prinAndLoanTypeList, TransBizConstant.ACCOUNTING_PHASE_2,
                table.getPrincipalDeadFlag(), table.getDeadDays(), TransBizConstant.TXN_CODE_PRIN_TRAN_DEAD, TransBizConstant.EVENT_CODE_T2));
        //本金,订单会计状态-呆账
        delqParamBean.getDelqAccountBeanList().add(new DelqAccountBean(prinAndLoanTypeList, TransBizConstant.ACCOUNTING_PHASE_3,
                table.getPrincipalBadFlag(), table.getBadDays(), TransBizConstant.TXN_CODE_PRIN_TRAN_BAD, TransBizConstant.EVENT_CODE_T3));
        //利息-正常
        delqParamBean.getDelqAccountBeanList().add(new DelqAccountBean(intrTypeList, TransBizConstant.ACCOUNTING_PHASE_0,
                TransBizConstant.TRANSFER_FLAG_1, 0, TransBizConstant.TXN_CODE_INTR_TRAN_NOMAL, TransBizConstant.EVENT_CODE_T0));
        //利息
        delqParamBean.getDelqAccountBeanList().add(new DelqAccountBean(intrTypeList, TransBizConstant.ACCOUNTING_PHASE_1,
                table.getInterestOverdueFlag(), table.getOverdueDays(), TransBizConstant.TXN_CODE_INTR_TRAN_OVER, TransBizConstant.EVENT_CODE_T1));
        //罚息/复利会计状态-逾期
        delqParamBean.getDelqAccountBeanList().add(new DelqAccountBean(pentIntrTypeList, TransBizConstant.ACCOUNTING_PHASE_1,
                TransBizConstant.TRANSFER_FLAG_1, 0, TransBizConstant.TXN_CODE_INTR_TRAN_OVER, TransBizConstant.EVENT_CODE_T1));

        //五级分类-正常
        delqParamBean.getDelqClassifyBeanList().add(new DelqClassifyBean(TransBizConstant.LOAN_CLASSIFY_0, 0, table.getClassifyReversible()));
        //五级分类-关注
        delqParamBean.getDelqClassifyBeanList().add(new DelqClassifyBean(TransBizConstant.LOAN_CLASSIFY_1, table.getClassify1Days(), table.getClassifyReversible()));
        //五级分类-次级
        delqParamBean.getDelqClassifyBeanList().add(new DelqClassifyBean(TransBizConstant.LOAN_CLASSIFY_2, table.getClassify2Days(), table.getClassifyReversible()));
        //五级分类-可疑
        delqParamBean.getDelqClassifyBeanList().add(new DelqClassifyBean(TransBizConstant.LOAN_CLASSIFY_3, table.getClassify3Days(), table.getClassifyReversible()));
        //五级分类-损失
        delqParamBean.getDelqClassifyBeanList().add(new DelqClassifyBean(TransBizConstant.LOAN_CLASSIFY_4, table.getClassify4Days(), table.getClassifyReversible()));

        //应计/非应计-订单交易
        delqParamBean.getDelqNonAccrualBeanMap().put(TransBizConstant.ACCOUNT_TYPE_05, new DelqNonAccrualBean(table.getPrincipalTransferType()
                , "1", TransBizConstant.TXN_CODE_PRIN_TRAN_NON, TransBizConstant.TXN_CODE_PRIN_TRAN_INNON, "", "", table.getNonAccrualsDays()));
        //应计/非应计-本金交易
        delqParamBean.getDelqNonAccrualBeanMap().put(TransBizConstant.ACCOUNT_TYPE_06, new DelqNonAccrualBean(table.getPrincipalTransferType()
                , table.getPrincipalNonAccrualsFlag(), TransBizConstant.TXN_CODE_PRIN_TRAN_NON, TransBizConstant.TXN_CODE_PRIN_TRAN_INNON, "", "", table.getNonAccrualsDays()));
        //应计/非应计-利息交易
        delqParamBean.getDelqNonAccrualBeanMap().put(TransBizConstant.ACCOUNT_TYPE_04, new DelqNonAccrualBean(table.getInterestTransferType()
                , table.getInterestNonAccrualsFlag(), TransBizConstant.TXN_CODE_INTR_TRAN_NON, TransBizConstant.TXN_CODE_INTR_TRAN_INNON, TransBizConstant.TXN_CODE_INTR_TAX_TRAN_NON
                , TransBizConstant.TXN_CODE_INTR_TAX_TRAN_INNON, table.getNonAccrualsDays()));
        //应计/非应计-利息累计
        delqParamBean.getDelqNonAccrualBeanMap().put(TransBizConstant.INTEREST_ACCRUAL_TYPE_66, new DelqNonAccrualBean(table.getInterestTransferType()
                , table.getInterestNonAccrualsFlag(), TransBizConstant.TXN_CODE_ACCU_INTR_TRAN_NON, TransBizConstant.TXN_CODE_ACCU_INTR_TRAN_INNON, TransBizConstant.TXN_CODE_ACCU_INTR_TAX_TRAN_NON
                , TransBizConstant.TXN_CODE_ACCU_INTR_TAX_TRAN_INNON, table.getNonAccrualsDays()));
        //应计/非应计-罚息交易
        delqParamBean.getDelqNonAccrualBeanMap().put(TransBizConstant.ACCOUNT_TYPE_11, new DelqNonAccrualBean(table.getPenaltyTransferType()
                , table.getPenaltyNonAccrualsFlag(), TransBizConstant.TXN_CODE_PENT_INTR_TRAN_NON, TransBizConstant.TXN_CODE_PENT_INTR_TRAN_INNON, TransBizConstant.TXN_CODE_PENT_INTR_TAX_TRAN_NON
                , TransBizConstant.TXN_CODE_PENT_INTR_TAX_TRAN_INNON, table.getNonAccrualsDays()));
        //应计/非应计-罚息累计
        delqParamBean.getDelqNonAccrualBeanMap().put(TransBizConstant.INTEREST_ACCRUAL_TYPE_10, new DelqNonAccrualBean(table.getPenaltyTransferType()
                , table.getPenaltyNonAccrualsFlag(), TransBizConstant.TXN_CODE_ACCU_PENT_INTR_TRAN_NON, TransBizConstant.TXN_CODE_ACCU_PENT_INTR_TRAN_INNON, TransBizConstant.TXN_CODE_ACCU_PENT_INTR_TAX_TRAN_NON
                , TransBizConstant.TXN_CODE_ACCU_PENT_INTR_TAX_TRAN_INNON, table.getNonAccrualsDays()));
        //应计/非应计-复利交易
        delqParamBean.getDelqNonAccrualBeanMap().put(TransBizConstant.ACCOUNT_TYPE_12, new DelqNonAccrualBean(table.getCompoundTransferType()
                , table.getCompoundNonAccrualsFlag(), TransBizConstant.TXN_CODE_COMP_INTR_TRAN_NON, TransBizConstant.TXN_CODE_COMP_INTR_TRAN_INNON
                , TransBizConstant.TXN_CODE_COMP_INTR_TAX_TRAN_NON, TransBizConstant.TXN_CODE_COMP_INTR_TAX_TRAN_INNON, table.getNonAccrualsDays()));
        //应计/非应计-复利累计
        delqParamBean.getDelqNonAccrualBeanMap().put(TransBizConstant.INTEREST_ACCRUAL_TYPE_20, new DelqNonAccrualBean(table.getCompoundTransferType()
                , table.getCompoundNonAccrualsFlag(), TransBizConstant.TXN_CODE_COMP_ACCU_INTR_TRAN_NON, TransBizConstant.TXN_CODE_COMP_ACCU_INTR_TRAN_INNON
                , TransBizConstant.TXN_CODE_COMP_ACCU_INTR_TAX_TRAN_NON, TransBizConstant.TXN_CODE_COMP_ACCU_INTR_TAX_TRAN_INNON, table.getNonAccrualsDays()));
        return delqParamBean;
    }

    /**
     * 构建延滞处理列表
     *
     * @param plan
     * @param businessDate
     * @return
     * @throws TxnBizException
     */
    @Override
    public BtDelqList buildBtDelqList(AmRepaymentPlanInfo plan, Date businessDate) throws TxnBizException {
        BtDelqList btDelqList = new BtDelqList();
        BeanMapping.copy(plan, btDelqList);
        try {
            btDelqList.setId(segmentService.getId(TransBizConstant.BT_DELQ_LIST_ID));
        } catch (SegmentException e) {
            logger.error("主键生成错误", e);
            throw new TxnBizException(TxnRespCode.ERROR.getUserTips());
        }

        btDelqList.setBusinessDate(businessDate);
        btDelqList.setCreateTime(null);
        btDelqList.setUpdateTime(null);
        btDelqList.setUpdateBy(TransBizConstant.SYS_OPRATE);
        return btDelqList;
    }

    /**
     * 构建延滞处理列表
     *
     * @param delq
     * @param businessDate
     * @return
     * @throws TxnBizException
     */
    @Override
    public BtDelqList buildBtDelqList(AmDelinquencyInfo delq, Date businessDate) throws TxnBizException {
        BtDelqList btDelqList = new BtDelqList();
        BeanMapping.copy(delq, btDelqList);
        try {
            btDelqList.setId(segmentService.getId(TransBizConstant.BT_DELQ_LIST_ID));
        } catch (SegmentException e) {
            logger.error("主键生成错误", e);
            throw new TxnBizException(TxnRespCode.ERROR.getUserTips());
        }

        btDelqList.setBusinessDate(businessDate);
        btDelqList.setCreateTime(null);
        btDelqList.setUpdateTime(null);
        btDelqList.setUpdateBy(TransBizConstant.SYS_OPRATE);
        return btDelqList;
    }

    /**
     * 延滞处理
     *
     * @param dealDelqBean
     * @return
     * @throws TxnBizException
     */
    @Override
    public DelqSaveBean dealDelq(DealDelqBean dealDelqBean) throws TxnBizException {
        DelqSaveBean delqSaveBean = new DelqSaveBean();
        AmRepaymentPlanInfo repaymentPlanInfo = dealDelqBean.getRepaymentPlanInfo();
        AmLoanMainInfo amLoanMainInfo = dealDelqBean.getLoanMain();
        AmLoanAccountInfo amLoanAccountInfo = dealDelqBean.getLoanAcct();
        Date businessDate = dealDelqBean.getBusinessDate();
        String customerId = repaymentPlanInfo.getCustomerId();
        String tenantId = repaymentPlanInfo.getTenantId();
        //逾期天数    当前处理日（today） - 还款日（payment_due_date） + 1
        Integer delqDays = DateUtils.getDiffDays(repaymentPlanInfo.getPaymentDueDate(), businessDate) + 1;

        PrDelqTable prDelqTable = delqTableService.findByDelqId(tenantId, amLoanMainInfo.getDelqTableId());

        //更新还款计划   逾期天数  状态
        AmRepaymentPlanInfo updatePlan = new AmRepaymentPlanInfo();
        updatePlan.setId(repaymentPlanInfo.getId());
        updatePlan.setLoanId(repaymentPlanInfo.getLoanId());
        updatePlan.setCustomerId(repaymentPlanInfo.getCustomerId());
        updatePlan.setTenantId(repaymentPlanInfo.getTenantId());
        //判断订单是否是核销订单并且根据延滞参数 核销后是否延滞处理标志 判断是否做延滞处理
        //逻辑更易理解
        if (TransBizConstant.YES_FLAG.equals(amLoanAccountInfo.getChargeoffFlag()) && TransBizConstant.NO_FLAG.equals(prDelqTable.getChargeoffDelqFlag())) {
            //不作处理
        } else {
            updatePlan.setDelqDays(delqDays);
        }

        //当前还款计划为正常状态
        if (TransBizConstant.LOAN_PLAN_STATUS_1.equals(repaymentPlanInfo.getPlanStatus())) {

            DelqSaveBean noDebtBean = this.dealNoDebt(dealDelqBean);
            if (null != noDebtBean) {
                return noDebtBean;
            }

            //生成延滞账户
            AmDelinquencyInfo delq = accountService.generateDelinquencyInfo(amLoanMainInfo, repaymentPlanInfo, businessDate, delqDays);
            delqSaveBean.setInsertDelq(delq);

            amLoanAccountInfo.setContinueOverDueTenor(amLoanAccountInfo.getContinueOverDueTenor() + 1);
            //判断订单是否是核销订单  核销订单不生成累计账户
            if (TransBizConstant.NO_FLAG.equals(amLoanAccountInfo.getChargeoffFlag())) {
                //生成罚息/复利累计账户
                PrPenaltyRateTable prPenaltyRateTable = prPenaltyRateTableService.findByPenaltyId(amLoanMainInfo.getPenaltyTableId(), amLoanMainInfo.getOrganizationId(), amLoanMainInfo.getTenantId());
                DelqParamBean delqParamBean = this.buildDqlqAccountBean(amLoanMainInfo.getTenantId(), amLoanMainInfo.getDelqTableId());
                List<AmInterestAccrualInfo> accrualList = accountService.castPenAndComAccrualAccount(repaymentPlanInfo, amLoanMainInfo, amLoanAccountInfo, prPenaltyRateTable, delqParamBean, null, businessDate);
                delqSaveBean.setAccrualList(accrualList);
            }

            //更新交易账户
            List<AmAccountMainInfo> acctList = dealDelqBean.getAcctList();

            if (CollectionUtils.isNotEmpty(acctList)) {
                List<AmAccountMainInfo> updateList = acctList.stream().map(
                        acct -> {
                            AmAccountMainInfo updateAcct = new AmAccountMainInfo();
                            updateAcct.setId(acct.getId());
                            updateAcct.setCustomerId(acct.getCustomerId());
                            updateAcct.setTenantId(acct.getTenantId());
                            updateAcct.setAccountStatus(TransBizConstant.ACCOUNT_STATUS_2);
                            acct.setAccountStatus(TransBizConstant.ACCOUNT_STATUS_2);
                            return updateAcct;
                        }
                ).collect(Collectors.toList());
                delqSaveBean.setUpdateAcctList(updateList);
            }

            //更新还款计划   当期逾期金额
            updatePlan.setOverDueAmount(delq.getTotalAmountDue());
            updatePlan.setPlanStatus(TransBizConstant.LOAN_PLAN_STATUS_2);

            //更新订单
            AmLoanAccountInfo updateLoan = new AmLoanAccountInfo();
            updateLoan.setId(amLoanAccountInfo.getId());
            updateLoan.setTenantId(amLoanAccountInfo.getTenantId());
            updateLoan.setCustomerId(amLoanAccountInfo.getCustomerId());
            updateLoan.setLoanId(amLoanAccountInfo.getLoanId());
            //状态
            updateLoan.setAccountStatus(TransBizConstant.LOAN_STATUS_2);
            //连续逾期期数
            updateLoan.setContinueOverDueTenor(amLoanAccountInfo.getContinueOverDueTenor());
            //总逾期期数
            updateLoan.setTotalOverDueTenor(amLoanAccountInfo.getTotalOverDueTenor() + 1);

            delqSaveBean.setUpdateLoan(updateLoan);
        } else {//当前还款计划为逾期状态   更新延滞账户、

            if (TransBizConstant.YES_FLAG.equals(amLoanAccountInfo.getChargeoffFlag()) && TransBizConstant.NO_FLAG.equals(prDelqTable.getChargeoffDelqFlag())) {
                return null;
            }

            //获取对应罚息参数
            PrPenaltyRateTable prPenaltyRateTable = prPenaltyRateTableService.findByPenaltyId(amLoanMainInfo.getPenaltyTableId(), amLoanMainInfo.getOrganizationId(), amLoanMainInfo.getTenantId());
            //罚息复利按月按月结息
            if (TransBizConstant.YES_FLAG.equals(prPenaltyRateTable.getCastPenaltyPerMonth())) {
                //判断是否当期还款日
                Boolean payDateFlag = DateUtils.checkPaymentDate(amLoanMainInfo.getFirstPaymentDate(), businessDate);

                if (payDateFlag) {
                    //生成罚息/复利累计账户
                    DelqParamBean delqParamBean = this.buildDqlqAccountBean(amLoanMainInfo.getTenantId(), amLoanMainInfo.getDelqTableId());
                    List<AmInterestAccrualInfo> accrualList = accountService.castPenAndComAccrualAccount(repaymentPlanInfo, amLoanMainInfo, amLoanAccountInfo, prPenaltyRateTable, delqParamBean, businessDate, businessDate);
                    delqSaveBean.setAccrualList(accrualList);
                }
            }

            AmDelinquencyInfo amDelinquencyInfo = dealDelqBean.getDelqAcct();
            Integer lastDelqDays = amDelinquencyInfo.getDelqDays();
            AmDelinquencyInfo updateDelq = new AmDelinquencyInfo();
            updateDelq.setId(amDelinquencyInfo.getId());
            updateDelq.setCustomerId(customerId);
            updateDelq.setTenantId(tenantId);
            updateDelq.setLastDelqDays(lastDelqDays);
            updateDelq.setDelqDays(delqDays);
            delqSaveBean.setUpdateDelq(updateDelq);
        }
        delqSaveBean.setUpdatePlan(updatePlan);
        return delqSaveBean;

    }

    /**
     * 处理当期无欠款订单
     *
     * @param dealDelqBean
     * @return
     */
    private DelqSaveBean dealNoDebt(DealDelqBean dealDelqBean) {
        AmLoanMainInfo amLoanMainInfo = dealDelqBean.getLoanMain();
        AmLoanAccountInfo amLoanAccountInfo = dealDelqBean.getLoanAcct();
        AmRepaymentPlanInfo repaymentPlanInfo = dealDelqBean.getRepaymentPlanInfo();
        List<AmAccountMainInfo> acctList = dealDelqBean.getAcctList();
        Date businessDate = dealDelqBean.getBusinessDate();

        //欠款计算
        BigDecimal debtAmt = repaymentPlanInfo.getTotalAmount().subtract(repaymentPlanInfo.getRepayPrincipal())
                .subtract(repaymentPlanInfo.getRepayInterest()).subtract(repaymentPlanInfo.getRepayFee());
        if (debtAmt.compareTo(BigDecimal.ZERO) > 0) {
            return null;
        }

        DelqSaveBean delqSaveBean = new DelqSaveBean();
        AmRepaymentPlanInfo updatePlan = new AmRepaymentPlanInfo();
        updatePlan.setId(repaymentPlanInfo.getId());
        updatePlan.setCustomerId(repaymentPlanInfo.getCustomerId());
        updatePlan.setTenantId(repaymentPlanInfo.getTenantId());
        updatePlan.setLoanId(repaymentPlanInfo.getLoanId());
        updatePlan.setDelqDays(0);
        updatePlan.setPlanStatus(TransBizConstant.LOAN_PLAN_STATUS_8);
        updatePlan.setPaymentDueDate(businessDate);
        delqSaveBean.setUpdatePlan(updatePlan);

        AmLoanAccountInfo updateLoan = new AmLoanAccountInfo();
        updateLoan.setId(amLoanAccountInfo.getId());
        updateLoan.setCustomerId(amLoanAccountInfo.getCustomerId());
        updateLoan.setTenantId(amLoanAccountInfo.getTenantId());
        updateLoan.setPayedTenor(amLoanAccountInfo.getPayedTenor() + 1);
        if (repaymentPlanInfo.getBillingTenor().intValue() == amLoanMainInfo.getTotalTenor().intValue()) {
            updateLoan.setAccountStatus(TransBizConstant.ACCOUNT_STATUS_8);
            updateLoan.setPayoffDate(businessDate);
        }
        delqSaveBean.setUpdateLoan(updateLoan);
        //更新交易账户
        if (CollectionUtils.isNotEmpty(acctList)) {
            List<AmAccountMainInfo> updateList = acctList.stream().map(
                    acct -> {
                        AmAccountMainInfo updateAcct = new AmAccountMainInfo();
                        updateAcct.setId(acct.getId());
                        updateAcct.setCustomerId(acct.getCustomerId());
                        updateAcct.setTenantId(acct.getTenantId());
                        updateAcct.setAccountStatus(TransBizConstant.ACCOUNT_STATUS_8);
                        return updateAcct;
                    }
            ).collect(Collectors.toList());
            delqSaveBean.setUpdateAcctList(updateList);
        }
        return delqSaveBean;

    }

    /**
     * 延滞外转列处理 会计状态升级，转非应计，五级分类升级
     *
     * @param dealTransOutBean
     * @return
     * @throws TxnException
     */
    @Override
    public DelqTransOutSaveBean dealDelqTransOut(DealTransOutBean dealTransOutBean) throws TxnException {
        DelqTransOutSaveBean saveBean = new DelqTransOutSaveBean();

        AmLoanAccountInfo loanAcct = dealTransOutBean.getLoanAcct();
        Date businessDate = dealTransOutBean.getBusinessDate();
        String loanId = loanAcct.getLoanId();
        String tenantId = loanAcct.getTenantId();

        //查询逾期还款计划
        List<AmRepaymentPlanInfo> planInfoList = dealTransOutBean.getPlanInfoList().stream()
                .filter(planInfo -> loanId.equals(planInfo.getLoanId()))
                .filter(planInfo -> Arrays.asList(TransBizConstant.LOAN_PLAN_STATUS_1, TransBizConstant.LOAN_PLAN_STATUS_2).contains(planInfo.getPlanStatus()))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(planInfoList)) {
            logger.info("DelqTransOut处理还款计划为空");
            throw new TxnException(TxnRespCode.NO_DATA.getCode(), TxnRespCode.NO_DATA.getUserTips());
        }

        //最大逾期天数
        int delqMaxDays = planInfoList.stream()
                .map(AmRepaymentPlanInfo::getDelqDays)
                .max(Integer::compareTo)
                .orElse(0);

        AmLoanMainInfo amLoanMainInfo = dealTransOutBean.getLoanMain();
        //延滞参数
        DelqParamBean delqParamBean = this.buildDqlqAccountBean(tenantId, amLoanMainInfo.getDelqTableId());

        List<TransferBean> transferBeanList = new ArrayList<>();
        planInfoList.forEach(
                plan -> {
                    int delqDays = plan.getDelqDays();
                    int billingTenor = plan.getBillingTenor();
                    //交易账户外转列处理 会计状态升级，转非应计，五级分类升级
                    List<AmAccountMainInfo> acctList = dealTransOutBean.getAcctList().stream()
                            .filter(acct -> loanId.equals(acct.getLoanId()))
                            .filter(acct -> billingTenor == acct.getBillingTenor())
                            .filter(acct -> Arrays.asList(TransBizConstant.ACCOUNT_TYPE_04, TransBizConstant.ACCOUNT_TYPE_06,
                                    TransBizConstant.ACCOUNT_TYPE_11, TransBizConstant.ACCOUNT_TYPE_12).contains(acct.getAccountType()))
                            .filter(acct -> Arrays.asList(TransBizConstant.ACCOUNT_STATUS_1, TransBizConstant.ACCOUNT_STATUS_2).contains(acct.getAccountStatus()))
                            .collect(Collectors.toList());

                    if (CollectionUtils.isNotEmpty(acctList)) {
                        acctList.stream()
                                .map(acct -> new TransferBean<>(acct).setAccountType(acct.getAccountType()).setDelqDays(delqDays))
                                .forEach(transferBeanList::add);
                    }

                    //累计账户外转列处理 会计状态升级，转非应计，五级分类升级
                    List<AmInterestAccrualInfo> accuAcctList = dealTransOutBean.getAccuAcctList().stream()
                            .filter(acct -> Arrays.asList(TransBizConstant.INTEREST_ACCRUAL_TYPE_66, TransBizConstant.INTEREST_ACCRUAL_TYPE_20,
                                    TransBizConstant.INTEREST_ACCRUAL_TYPE_10).contains(acct.getAccountType()))
                            .filter(acct -> billingTenor == acct.getBillingTenor())
                            .filter(acct -> loanId.equals(acct.getLoanId()))
                            .filter(acct -> TransBizConstant.INTEREST_ACCRUAL_STATUS_1.equals(acct.getAccountStatus()))
                            .collect(Collectors.toList());

                    if (CollectionUtils.isNotEmpty(accuAcctList)) {
                        accuAcctList.stream()
                                .map(accuAcct -> new TransferBean<>(accuAcct).setAccountType(accuAcct.getAccountType()).setDelqDays(delqDays))
                                .forEach(transferBeanList::add);
                    }
                }

        );

        //订单外转列处理 会计状态升级，转非应计，五级分类升级
        transferBeanList.add(new TransferBean<>(loanAcct).setAccountType(TransBizConstant.ACCOUNT_TYPE_05).setDelqDays(delqMaxDays));
        UncheckedFunction<TransferBean, TransferSaveBean> transfer = transferBean -> {
            transferBean.setDelqParamBean(delqParamBean).setMaxDelqDays(delqMaxDays).setBussinessDate(businessDate).setAmLoanMainInfo(amLoanMainInfo);
            String transferMethod = delqParamBean.getDelqNonAccrualBeanMap().get(transferBean.getAccountType()).getTransferMethod();
            TransferBean trans = strategySelector.selectMethodStrategy(transferMethod).transferOut(transferBean);
            TransferSaveBean transferSaveBean = strategySelector.selectTypeStrategy(transferBean.getTransferObject()).transferOut(trans);
            return transferSaveBean;
        };

        transferBeanList.stream()
                .map(CollectorsUtils.tranToUncheck(transfer))
                .filter(Objects::nonNull)
                .forEach(saveBean.getTransferSaveBeanList()::add);
        return saveBean;
    }

    /**
     * 延滞内转列处理 会计状态降级，转应计，五级分类降级
     *
     * @param dealTransInBean
     * @return
     * @throws TxnException
     */
    @Override
    public DelqTransInSaveBean dealDelqTransIn(DealTransInBean dealTransInBean) throws TxnException {
        DelqTransInSaveBean saveBean = new DelqTransInSaveBean();

        AmLoanAccountInfo loanAcct = dealTransInBean.getLoanAcct();
        Date businessDate = dealTransInBean.getBusinessDate();
        String loanId = loanAcct.getLoanId();
        String tenantId = loanAcct.getTenantId();

        //查询逾期还款计划
        List<AmRepaymentPlanInfo> planInfoList = dealTransInBean.getPlanInfoList().stream()
                .filter(planInfo -> loanId.equals(planInfo.getLoanId()))
                .filter(planInfo -> Arrays.asList(TransBizConstant.LOAN_PLAN_STATUS_1, TransBizConstant.LOAN_PLAN_STATUS_2).contains(planInfo.getPlanStatus()))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(planInfoList)) {
            logger.info("DelqTransIn处理还款计划为空");
            return null;
        }

        //最大逾期天数
        int delqMaxDays = planInfoList.stream()
                .map(AmRepaymentPlanInfo::getDelqDays)
                .max(Integer::compareTo)
                .orElse(0);

        AmLoanMainInfo amLoanMainInfo = dealTransInBean.getLoanMain();
        //延滞参数 加入五级参数是否可逆属性
        DelqParamBean delqParamBean = this.buildDqlqAccountBean(tenantId, amLoanMainInfo.getDelqTableId());

        List<TransferBean> transferBeanList = new ArrayList<>();
        planInfoList.forEach(
                plan -> {
                    int delqDays = plan.getDelqDays();
                    int billingTenor = plan.getBillingTenor();
                    //交易账户内转列处理 会计状态将级，转应计，五级分类降级
                    List<AmAccountMainInfo> acctList = dealTransInBean.getAcctList().stream()
                            .filter(acct -> loanId.equals(acct.getLoanId()))
                            .filter(acct -> billingTenor == acct.getBillingTenor())
                            .filter(acct -> Arrays.asList(TransBizConstant.ACCOUNT_TYPE_04, TransBizConstant.ACCOUNT_TYPE_06,
                                    TransBizConstant.ACCOUNT_TYPE_11, TransBizConstant.ACCOUNT_TYPE_12).contains(acct.getAccountType()))
                            .filter(acct -> Arrays.asList(TransBizConstant.ACCOUNT_STATUS_1, TransBizConstant.ACCOUNT_STATUS_2).contains(acct.getAccountStatus()))
                            .collect(Collectors.toList());

                    if (CollectionUtils.isNotEmpty(acctList)) {
                        acctList.stream()
                                .map(acct -> new TransferBean<>(acct).setAccountType(acct.getAccountType()).setDelqDays(delqDays))
                                .forEach(transferBeanList::add);
                    }

                    //累计账户内转列处理 会计状态将级，转应计，五级分类降级
                    List<AmInterestAccrualInfo> accuAcctList = dealTransInBean.getAccuAcctList().stream()
                            .filter(acct -> Arrays.asList(TransBizConstant.INTEREST_ACCRUAL_TYPE_66, TransBizConstant.INTEREST_ACCRUAL_TYPE_20,
                                    TransBizConstant.INTEREST_ACCRUAL_TYPE_10).contains(acct.getAccountType()))
                            .filter(acct -> billingTenor == acct.getBillingTenor())
                            .filter(acct -> loanId.equals(acct.getLoanId()))
                            .filter(acct -> TransBizConstant.INTEREST_ACCRUAL_STATUS_1.equals(acct.getAccountStatus()))
                            .collect(Collectors.toList());

                    if (CollectionUtils.isNotEmpty(accuAcctList)) {
                        accuAcctList.stream()
                                .map(accuAcct -> new TransferBean<>(accuAcct).setAccountType(accuAcct.getAccountType()).setDelqDays(delqDays))
                                .forEach(transferBeanList::add);
                    }
                }

        );

        //订单内转列处理 会计状态将级，转应计，五级分类降级
        transferBeanList.add(new TransferBean<>(loanAcct).setAccountType(TransBizConstant.ACCOUNT_TYPE_05).setDelqDays(delqMaxDays));
        UncheckedFunction<TransferBean, TransferSaveBean> transfer = transferBean -> {
            transferBean.setDelqParamBean(delqParamBean).setMaxDelqDays(delqMaxDays).setBussinessDate(businessDate).setAmLoanMainInfo(amLoanMainInfo);
            logger.info("1111{},{}", delqParamBean.getDelqNonAccrualBeanMap(), transferBean.getAccountType());
            String transferMethod = delqParamBean.getDelqNonAccrualBeanMap().get(transferBean.getAccountType()).getTransferMethod();
            TransferBean trans = strategySelector.selectMethodStrategy(transferMethod).transferIn(transferBean);
            TransferSaveBean transferSaveBean = strategySelector.selectTypeStrategy(transferBean.getTransferObject()).transferIn(trans);
            return transferSaveBean;
        };

        transferBeanList.stream()
                .map(CollectorsUtils.tranToUncheck(transfer))
                .filter(Objects::nonNull)
                .forEach(saveBean.getTransferSaveBeanList()::add);
        return saveBean;
    }
}
